/**
 * 取得语言
 * @config $._lang_maps [配置]语言映射 {key:val, ...}
 * 		若key语言未定义,则使用val语言  小写,'_'分割
 * 		优先: 全名 > 映射全名 > 映射前缀('_'分割首个)
 * 		前缀名: {zh:'zh_cn'}, 未定义`zh_*`全用`zh_cn`
 * @config $._lang_last [配置]最终语言  未匹配时使用
 * @config $._lang_able [配置]默认语言  参数:s=null时
 * @param lang string 语言编码  "{p}.{key}"
 * @param args json|null 语言模板参数
 * @param s array|null 接受语言 优先排序
 * 		若为null: 则取 $._lang_able||$.lang.able()
 * @return string
 */
$.lang = function(lang, args=null, s=null){
	const S=lang.split('.'), K=S.pop(), P=S.join('.');
	const T=$.__lang[P], M=$._lang_maps;  let v;
	s = s||$._lang_able||($._lang_able=$.lang.able());
	for(let t of s){ // 取语言模板
		v = T[t] || T[M[t]] || T[M[t.split('_')[0]]];
		if(v){ v=v[K]; break; } // 前缀映射->值限全名
	}
	const RE = k=>v=v.replaceAll(`{${k}}`,args[k]);
	if(args) Object.keys(args).forEach(RE); return v;
};
/**
 * 计算接受的语言类型
 * @param most string|null 最优先语言
 * 		通常为用户指定(选择)的最优先语言
 * @param able array|null 客户端接受语言
 * 		null: 自动取当前运行环境语言信息
 * @param last array|null 最终支持语言
 * 		null: 则取配置 -> $._lang_last
 * 		在most,able均未匹配时使用的语言
 * @return array  '-'转为'_',小写,去重
 */
$.lang.able = function(most=null, able=null, last=null){
	let rtn=[];  if(!last) last=$._lang_last;
	if(able) rtn=able.slice(0); else if(GEN.RUN){
		const M=process.env;  let v=M.LANG||M.LC_ALL;
		v=v||M.LC_CTYPE;  rtn=v?[v.split('.')[0]]:[];
	}
	else if(typeof navigator!=='undefined'){
		let s=navigator.languages; rtn=s?s.slice(0):[];
	}
	if(most) rtn.unshift(most);  rtn.push(...last);
	rtn=rtn.map(v=>v.replace('-','_').toLowerCase());
	return $.auv(rtn);
};
// 注册语言  $.lang("{p}.{m.{语言类型}的KEY}", ...)
$._lang = (p,m)=>$.__lang[p]=$.mix($.__lang[p],m);
Object.defineProperty($,'__lang',{value:{}});//缓存
$._lang_maps=$._lang_maps||{}; //[配置]语言类型映射
$._lang_last=$._lang_last||['zh_cn'];//[配置]最终语言
$._lang_able=$._lang_able||null; //[配置]默认语言
